package synchronization;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
import DataModel.NotaryEntry;
import SynchronizationLayer.ConversationGroup;
import SynchronizationLayer.ISynchronizationServer;
import SynchronizationLayer.NotarySynchronizationMessage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import Repository.IRepositoryProxy;
import java.util.concurrent.ExecutorService;
import tenorserver.TenorServerSettings;

/**
 *
 * @author Tomasz Nowak
 */
public class SynchronizationServer implements ISynchronizationServer
{
	java.net.DatagramSocket socket;
	IRepositoryProxy repositoryProxy;

	Thread receivingThread;
	ConversationGroup[] conversationGroups;
	ExecutorService executorService;

	public IRepositoryProxy getRepositoryProxy()
	{
		return repositoryProxy;
	}

	public void setRepositoryProxy( IRepositoryProxy repositoryProxy )
	{
		this.repositoryProxy = repositoryProxy;
	}

	public SynchronizationServer( TenorServerSettings generalSettings, IRepositoryProxy repository, ConversationGroup[] conversationGroups ) throws SocketException
	{
		repositoryProxy = repository;
		generalSettings.load();
		socket = new DatagramSocket(generalSettings.getPort(),
																generalSettings.getListeningAddress());

		this.conversationGroups = conversationGroups;
		this.executorService = Executors.newCachedThreadPool();
	}

	@Override
	public void startReceivingRequests()
	{
		receivingThread = new Thread(new SynchronizationServerReceiver(socket, repositoryProxy, conversationGroups, this));

		receivingThread.start();
	}

	@Override
	public void sendResponse( final NotarySynchronizationMessage notarySynchronizationMessage, final InetAddress address, final int port ) throws IOException, ClassNotFoundException
	{
		Executor executor = Executors.newSingleThreadExecutor();

		executor.execute(new Runnable()
		{
			@Override
			public void run()
			{
				ObjectOutputStream objectOutputStream = null;
				try
				{
					ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
					objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
					objectOutputStream.writeObject(notarySynchronizationMessage);
					objectOutputStream.flush();
					byte[] buffer = byteArrayOutputStream.toByteArray();
					byte[] packetbuffer = new byte[buffer.length + 2];
					byte[] lengthArray = ByteBuffer.allocate(4).putInt(buffer.length).array();
					packetbuffer[0] = lengthArray[2];
					packetbuffer[0] = lengthArray[3];
					DatagramPacket packet = new DatagramPacket(packetbuffer, packetbuffer.length, address, port);
					socket.send(packet);
				}
				catch ( IOException ex )
				{
					Logger.getLogger(SynchronizationServer.class.getName()).log(Level.SEVERE, null, ex);
				}
				finally
				{
					try
					{
						objectOutputStream.close();
					}
					catch ( IOException ex )
					{
						Logger.getLogger(SynchronizationServer.class.getName()).log(Level.SEVERE, null, ex);
					}
				}
			}
		});
	}

	@Override
	public void synchronize()
	{
		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
	}

	@Override
	public void revoke( NotaryEntry entry )
	{
		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
	}

	@Override
	public void register( NotaryEntry entry )
	{
		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
	}
}
